package cn.neo.hhrpc.core.consumer;


import cn.neo.hhrpc.core.annotation.HHConsumer;
import cn.neo.hhrpc.core.api.*;
import cn.neo.hhrpc.core.meta.InstanceMeta;
import cn.neo.hhrpc.core.meta.ServiceMeta;
import cn.neo.hhrpc.core.registry.RegistryCenter;
import cn.neo.hhrpc.core.util.MethodUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.*;

@Data
@Slf4j
public class ConsumerBootstrap implements ApplicationContextAware, EnvironmentAware {

    ApplicationContext applicationContext;
    Environment environment;

    private Map<String, Object> stub = new HashMap<>();

    /**
     * 创建@HHConsumer注解下的UserService代理类
     */
    public void start() {

        RegistryCenter rc = applicationContext.getBean(RegistryCenter.class);
        RpcContext context = applicationContext.getBean(RpcContext.class);
        // 在spring 上下文中，同样的类型有多个 bean，使用 getBeansOfType
//        List<Filter> filters = applicationContext.getBeansOfType(Filter.class).values().stream().toList();

        // 获取所有的bean名称
        String[] names = applicationContext.getBeanDefinitionNames();
        for (String name : names) {
            // 获取bean实例
            Object bean = applicationContext.getBean(name);
            // 获取加了@HHConsumer注解的field
            List<Field> fields = MethodUtils.findAnnotatedField(bean.getClass(), HHConsumer.class);
            // 针对此类对象创建代理
            fields.stream().forEach(f -> {
                // 接口类型
                Class<?> service = f.getType();
                // 接口全限定名
                String serviceName = service.getCanonicalName();
                log.info(" ===> " + f.getName());
                try {
                    Object consumer = stub.get(serviceName);
                    if (null == consumer) {
                        // 创建代理对象
                        consumer = createFromRegistry(service, context, rc);
                        stub.put(serviceName, consumer);
                    }
                    // 此处设为true，为了防止将代理对象塞给bean的过程中报错
                    f.setAccessible(true);
                    f.set(bean, consumer);
                } catch (Exception ex) {
                    log.warn(" ===> Field[{},{}] create consumer failed. ", serviceName, f.getName());
                    log.error("Ignore and print it as : ", ex);
                }
            });
        }
    }

    private Object createFromRegistry(Class<?> service, RpcContext context, RegistryCenter rc) {
        ServiceMeta serviceMeta = ServiceMeta.builder()
                .app(context.param("app.id"))
                .namespace(context.param("app.namespace"))
                .env(context.param("app.env"))
                .name(service.getCanonicalName())
                .build();

        // 获取所有服务列表
        List<InstanceMeta> providers = rc.fetchAll(serviceMeta);
        log.info(" ===> map to providers: ");
        providers.forEach(System.out::println);

        rc.subscribe(serviceMeta, event -> {
            providers.clear();
            providers.addAll(event.getData());
        });

        return createConsumer(service, context, providers);
    }


    private Object createConsumer(Class<?> service, RpcContext context, List<InstanceMeta> providers) {
        return Proxy.newProxyInstance(service.getClassLoader(), // 类的classLoader
                new Class[]{service}, // 接口类型
                new HHInvocationHandler(service, context, providers)); // 具体方法处理的拦截器
    }


}
